package emails

import (
	"../luahelper"
	"errors"
	"github.com/emersion/go-imap"
	lua "github.com/yuin/gopher-lua"
	//"strings"
)

func RegisterFunc_4lua(l *lua.LState) {
	table := l.SetFuncs(l.NewTable(), map[string]lua.LGFunction{
		"SendMessage":    SendMessage_4lua,
		"ReceiveMessage": ReceiveMessage_4lua,
		"Store":          MessageStore_4lua,
	})
	l.SetGlobal("Email", table)
}

func MessageStore_4lua(l *lua.LState) int {
	// Email.Store({
	// 	smtp = {
	// 		url = "smtp.qq.com:995",
	// 		useSSL = true
	// 	},
	// 	username = "anxin1225@126.com",
	// 	password = "123456"
	// }, 206, "+FLAGS", "\\Answered")

	emailSetting := l.ToTable(1)

	imapSetting, err := GetImapSettingFormLValue(emailSetting.RawGetString("imap"))
	if err != nil {
		return luahelper.PushErrorMessage(l, err.Error())
	}

	userInfo, err := GetUserInfoFromTable(emailSetting)
	if err != nil {
		return luahelper.PushErrorMessage(l, err.Error())
	}

	seq := uint32(l.ToNumber(2))
	storeItem := imap.StoreItem(l.ToString(3))
	value := l.ToString(4)

	err = MessageStore(imapSetting, userInfo, seq, storeItem, value)
	if err != nil {
		return luahelper.PushErrorMessage(l, err.Error())
	}

	return luahelper.PushStatus(l, true)
}

func SendMessage_4lua(l *lua.LState) int {
	// Email.SendMessage({
	// 	smtp = {
	// 		url = "smtp.qq.com:995",
	// 		useSSL = true
	// 	},
	// 	username = "anxin1225@126.com",
	// 	password = "123456"
	// }, {
	// 	display = "DutyRobot",
	// 	to = {
	// 		"anxin1225@126.com"
	// 	},
	// 	subject = "Hello",
	// 	body = "this is body"
	// })

	emailSettingTable := l.ToTable(1)
	emailTable := l.ToTable(2)

	toUserList := []string{}
	if toUserListTable, ok := emailTable.RawGetString("to").(*lua.LTable); ok {
		for i := 1; i <= toUserListTable.Len(); i++ {
			toUser := lua.LVAsString(toUserListTable.RawGetInt(i))
			if toUser != "" {
				toUserList = append(toUserList, toUser)
			}
		}
	}

	if len(toUserList) == 0 {
		return luahelper.PushErrorMessage(l, "not found to users")
	}

	smtpSetting, err := GetSmtpSettingFromTable(l.ToTable(1))
	if err != nil {
		return luahelper.PushErrorMessage(l, err.Error())
	}

	userInfo, err := GetUserInfoFromTable(emailSettingTable)
	if err != nil {
		return luahelper.PushErrorMessage(l, err.Error())
	}

	displayName := lua.LVAsString(emailTable.RawGetString("display"))
	if displayName == "" {
		return luahelper.PushErrorMessage(l, "not found display name")
	}

	subject := lua.LVAsString(emailTable.RawGetString("subject"))
	if subject == "" {
		return luahelper.PushErrorMessage(l, "not found subject")
	}

	body := lua.LVAsString(emailTable.RawGetString("body"))
	if body == "" {
		return luahelper.PushErrorMessage(l, "not found body")
	}

	SendMessage(smtpSetting, userInfo, toUserList, displayName, subject, body)
	return luahelper.PushStatus(l, true)
}

func ReceiveMessage_4lua(l *lua.LState) int {
	// Email.ReceiveMessage({
	// 	imap = {
	// 		url = "",
	// 		useSSL = true
	// 	},
	// 	username = "",
	// 	password = ""
	// }, function(msg){
	// 	...
	// })

	emailTable := l.ToTable(1)

	var imapTable *lua.LTable
	var ok bool
	if imapTable, ok = l.GetField(emailTable, "imap").(*lua.LTable); ok == false {
		return luahelper.PushErrorMessage(l, "not found imap in table")
	}

	imapSetting, err := GetImapSettingFromTable(imapTable)
	if err != nil {
		return luahelper.PushErrorMessage(l, err.Error())
	}

	userInfo, err := GetUserInfoFromTable(emailTable)
	if err != nil {
		return luahelper.PushErrorMessage(l, err.Error())
	}

	lFunc := l.ToFunction(2)

	if lFunc == nil {
		return luahelper.PushErrorMessage(l, "not found call back function")
	}

	err = ReceiveMessage(imapSetting, userInfo, func(message *Email) {
		table := ConvertEmail2LuaTable(l, message)

		l.CallByParam(lua.P{
			Fn:      lFunc,
			NRet:    0,
			Protect: true,
			Handler: nil,
		}, table)
	})

	if err != nil {
		return luahelper.PushErrorMessage(l, err.Error())
	}

	return 0
}

func GetSmtpSettingFromTable(table *lua.LTable) (setting *SmtpSetting, err error) {
	if smtpSettingTable, ok := table.RawGetString("smtp").(*lua.LTable); ok {
		setting = &SmtpSetting{
			Url:    lua.LVAsString(smtpSettingTable.RawGetString("url")),
			UseSSL: lua.LVAsBool(smtpSettingTable.RawGetString("useSSL")),
		}
	}

	if setting == nil {
		//return luahelper.PushErrorMessage(l, "not found smtp")
		err = errors.New("not found smtp")
		return
	}

	if setting.Url == "" {
		//return luahelper.PushErrorMessage(l, "not found smtp.url")
		err = errors.New("not found smtp.url")
		return
	}

	return
}

func GetUserInfoFromLValue(value lua.LValue) (info *UserInfo, err error) {
	if table, ok := value.(*lua.LTable); ok {
		return GetUserInfoFromTable(table)
	} else {
		err = errors.New("value was not a table")
		return
	}
}

func GetUserInfoFromTable(table *lua.LTable) (info *UserInfo, err error) {
	info = &UserInfo{
		UserName: lua.LVAsString(table.RawGetString("username")),
		Password: lua.LVAsString(table.RawGetString("password")),
	}
	if info.UserName == "" {
		//return luahelper.PushErrorMessage(l, "not found username")
		err = errors.New("not found username")
		return
	}

	if info.Password == "" {
		//return luahelper.PushErrorMessage(l, "not found password")
		err = errors.New("not found password")
		return
	}

	return
}

func GetImapSettingFormLValue(value lua.LValue) (setting *ImapSetting, err error) {
	if table, ok := value.(*lua.LTable); ok {
		return GetImapSettingFromTable(table)
	} else {
		err = errors.New("value is not a table")
		return
	}
}

func GetImapSettingFromTable(table *lua.LTable) (setting *ImapSetting, err error) {
	url := lua.LVAsString(table.RawGetString("url"))
	if url == "" {
		err = errors.New("not found url")
		return
	}

	useSSLLV := table.RawGetString("useSSL")
	if useSSLLV.Type() == lua.LTNil {
		err = errors.New("not found useSSL")
		return
	}

	setting = &ImapSetting{
		Url:    url,
		UseSSL: lua.LVAsBool(useSSLLV),
	}

	return
}

func ConvertEmail2LuaTable(l *lua.LState, email *Email) *lua.LTable {
	if email == nil {
		return nil
	}

	table := l.NewTable()

	if email.Subject != "" {
		l.SetField(table, "Subject", lua.LString(email.Subject))
	}

	l.SetField(table, "SeqNum", lua.LNumber(email.SeqNum))

	l.SetField(table, "DateTime", lua.LString(email.DateTime.Format("2006-01-02 15:04:05")))

	l.SetField(table, "MessageId", lua.LString(email.MessageId))

	//if email.HtmlBody != "" {
	//	l.SetField(table, "HtmlBody", lua.LString(email.HtmlBody))
	//}

	if email.TextBody != "" {
		l.SetField(table, "TextBody", lua.LString(email.TextBody))
	}

	if list := ConvertStringList2LuaTable(l, email.From); list != nil {
		l.SetField(table, "From", list)
	}

	if list := ConvertStringList2LuaTable(l, email.To); list != nil {
		l.SetField(table, "To", list)
	}

	return table
}

func ConvertStringList2LuaTable(l *lua.LState, address []string) *lua.LTable {
	if address == nil || len(address) == 0 {
		return nil
	}

	list := l.NewTable()

	for i, v := range address {
		l.SetTable(list, lua.LNumber(i+1), lua.LString(v))
	}

	return list
}
